import datetime
import datetime
import time

from fastapi import APIRouter, Body, Depends, Request
from peewee_async import Manager

from cache.tenant_cache import TenantCache
from common.config.settings import Settings
from common.g.g import (
    G_REDIS, G_LOGGER
)
from common.pkg.jwt_util import generate_jwt_token
from common.route.user_route import TenantMustLoginAPIRoute
from common.utils.depends.common import (
    get_mgw,
    get_settings,
    get_current_user_id, get_request_id, get_current_user
)
from common.utils.depends.tips_depends import get_auth_code
from common.utils.lock.lock import release_lock
from common.utils.lock.lock_dec import lock
from common.utils.resp import JsonResponse, RC
from common.utils.tenant_utils import set_tenant_cookie
from common.pkg.fastapi_util import cbv
from core.view import TenantBaseView
from common.v.v import TENANT
from schema.req_schema.tenant_user_req_schema import TenantUserRegisterModel, TenantUserLoginModel, LoginTypeEnum
from schema.resp_schema.tenant_user_schema import CurrentUserInfoResponseModel
from service.tenant_service import TenantUserService

router = APIRouter(prefix="/user", tags=["user"])

login_router = APIRouter(prefix="/user",
                         tags=["user"],
                         route_class=TenantMustLoginAPIRoute)

@cbv(router)
class UserView(TenantBaseView):

    @router.post("/register", description="租户账号注册,目前仅支持邮箱注册,所以邮箱必填")
    async def user_register(self, register_data: TenantUserRegisterModel = Body(...)):
        tus = TenantUserService(self.mgw, self.redis)
        lock_key = f"email:{register_data.email}"
        lock_value = self.request_id
        lock_time = 30  # 30ms
        execute_time = 2000  # 2000ms
        res = await lock(lock_key, lock_value, lock_time, execute_time)(tus.register)(register_data)
        if res is None:
            return JsonResponse().inner_error(msg="服务异常")
        else:
            ok, data_or_code = res
            return self.unpack_response(ok, data_or_code)

    @router.post("/login", description="租户账号登陆")
    async def user_login(self,
                         request: Request,
                         login_data: TenantUserLoginModel = Body(...),
                         settings: Settings = Depends(get_settings),
                         ):
        tenant_id = request.headers.get("TENANT")
        if login_data.login_type in (LoginTypeEnum.PHONE_WITH_VERIFY_CODE, LoginTypeEnum.EMAIL_WITH_VERIFY_CODE):
            # 走验证码
            ...
        else:
            login_dict_data = login_data.dict(exclude_none=True)
            login_dict_data.pop("login_type", None)
            tus = TenantUserService(self.mgw, self.redis)
            user = await tus.get_user_info_by_condition(**login_dict_data)
            if not user:
                return JsonResponse(code=RC.NOT_EXIST, msg="用户名或者密码错误").to_response()
            if tenant_id:
                res = await tus.is_user_exist(tenant_id, user.get("user_id"))
                if not res:
                    resp = JsonResponse(code=RC.FORBIDDING, msg="当前用户无法选择该商户").to_response()
                    return resp
            payload = {"username": user.get("username"), "user_id": user.get("user_id"),
                       "exp": time.time() + settings.jwt_config.timeout}
            token = generate_jwt_token(payload, secret=settings.jwt_config.tenant_secret,
                                       algorithm=settings.jwt_config.algorithms)
            try:
                await tus.update(user.get("user_id"), user.get("version"), last_login=datetime.datetime.now())
            except Exception as e:
                G_LOGGER.exception(f"更新最后登陆时间异常:{e}")
            resp = JsonResponse(data={"token": token}).to_response()
            if tenant_id:
                resp = set_tenant_cookie(resp, tenant_id)
            return resp


@cbv(login_router)
class LoginedUserView(TenantBaseView):
    @login_router.get("/tenants", description="获取当前登陆用户所属的租户列表", dependencies=[Depends(get_auth_code)])
    async def get_current_tenants(self):
        tus = TenantUserService(self.mgw, self.redis)
        ok, data_or_code = await tus.get_tenants_info(self.user_id)
        return self.unpack_response(ok, data_or_code)

    @login_router.post("/choice_tenant", description="选择需要登陆的租户,当一个用户所属的租户超过一个的时候,登陆之后需要选择一个租户进行登陆", dependencies=[Depends(get_auth_code)])
    async def choice_tenant(self, tenant_id: int = Body(..., embed=True)):
        exist = await TenantCache(self.redis).sismember(TENANT.TENANT_USER_SET.format(tenant_id=tenant_id), self.user_id)
        if exist:
            resp = JsonResponse().to_response()
            resp = set_tenant_cookie(resp, tenant_id)
            return resp
        else:
            return JsonResponse(code=RC.FORBIDDING, msg="当前用户无法选择该商户").to_response()

    @login_router.get("/current", description="获取当前登陆用户信息", dependencies=[Depends(get_auth_code)], response_model=CurrentUserInfoResponseModel)
    async def get_current_user_info(self, user: dict = Depends(get_current_user)):
        return CurrentUserInfoResponseModel(data=user)


